const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void async function () {
    line = await readline()
    let [m, n] = line.split(' ').map((i) => parseInt(i)),
        pathArr = [],
        parent = new Array(m + 1).fill(0).map((val, index) => index),
        count = 0;
    // 初始化原本边的数组
    while (line = await readline()) {
        pathArr.push(line.split(' ').map(Number))
    }
    // 按照边的权值进行从小到大排序
    pathArr.sort((a, b) => a[2] - b[2])

    for (let [l, r, v] of pathArr) {
        // 如果两个节点不在一个集合中，则加入（不形成环），从小到大建立新边
        if (find(parent, l) === find(parent, r)) {
            continue
        }
        join(parent, l, r)
        count++
    }
    console.log(count)
}()

// 基于并查集
const find = (parent, a) => {
    return a === parent[a] ? a : parent[a] = find(parent, parent[a])
}

const join = (parent, a, b) => {
    a = find(parent, a)
    b = find(parent, b)
    if (a === b) return
    parent[b] = a
}